package com.onlinesys.protocol.serial;

import gnu.io.CommPort;
import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.TooManyListenersException;

import com.onlinesys.protocol.ConfigManager;
import com.onlinesys.protocol.ProtocolConstant;
import com.onlinesys.protocol.exceptions.ProtocolException;
import com.onlinesys.protocol.utils.ProtocolUtils;

/**
 * This version of the TwoWaySerialComm example makes use of the
 * SerialPortEventListener to avoid polling.
 * 
 */
public class SerialComm {
    static OutputStream out;
    static InputStream in;
    SerialPort serialPort = null;

    public SerialComm() {
        super();
    }

    public void connect() throws ProtocolException{
        CommPortIdentifier portIdentifier = null;
        ConfigManager config = ConfigManager.getInstance();
        String serialPortStr = config.getConfig(ProtocolConstant.PARAMS_PORT, ProtocolConstant.PARAMS_DEFAULT_PORT_VALUE);
        try {
            portIdentifier = CommPortIdentifier.getPortIdentifier(serialPortStr);
        } catch (NoSuchPortException e) {
            System.out.println("SerialPort \"" + serialPortStr + "\" doesn't exist.");
            throw new ProtocolException("SerialPort: \"" + serialPortStr + "\" doesn't exist");
        }

        if (portIdentifier.isCurrentlyOwned()) {
            System.out.println("Error: Port is currently in use");
        } else {
            CommPort commPort = null;
            try {
                commPort = portIdentifier.open(this.getClass().getName(), 2000);
            } catch (PortInUseException e) {
                System.out.println("Error: Port is currently in use");
                throw new ProtocolException("Error: Port \"" + serialPortStr + "\" is currently in use");
            }

            if (commPort instanceof SerialPort) {
                serialPort = (SerialPort) commPort;
                try {
                    serialPort.setSerialPortParams(Integer.parseInt(config.getConfig(ProtocolConstant.PARAMS_RATE, ProtocolConstant.PARAMS_DEFAULT_RATE_VALUE)), SerialPort.DATABITS_8, SerialPort.STOPBITS_1,
                            SerialPort.PARITY_NONE);
                } catch (UnsupportedCommOperationException e) {
                    throw new ProtocolException(e);
                }

                try {
                    in = serialPort.getInputStream();
                    out = serialPort.getOutputStream();
                } catch (IOException e) {
                    throw new ProtocolException(e.getLocalizedMessage());
                }

                try {
                    serialPort.addEventListener(new SerialReader(in));
                } catch (TooManyListenersException e) {
                    throw new ProtocolException(e);
                }
                serialPort.notifyOnDataAvailable(true);

            } else {
                System.out.println("Only serial ports are handled");
                throw new ProtocolException(" Only serial ports are handled");
            }
        }
    }

    public synchronized static void writeData(byte[] data) throws IOException {
    	System.out.println("SerialComm sending data...");
    	ProtocolUtils.printData(data);
        out.write(data);
    }

    public synchronized void closePort() {
    	if (serialPort != null) {
    		serialPort.close();
    	}
    }
}